/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package logica.util;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import modelo.DTO.DTODataMining;
import modelo.DTO.DTOPerfilUnicoAlumno;
import weka.classifiers.lazy.IBk;
import weka.clusterers.ClusterEvaluation;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SelectedTag;


/**
 *
 * @author Ion B. Padilla
 */
public class ClassificateUtil {
    private Instances instancia,instanciasC,instanciasCEntera,instanciaEntera;
    private Attribute aCluster;
    private FastVector vectorAtributosC;
    private ArrayList<ArrayList<DTODataMining>> listaElementos;
    private ArrayList<Attribute> listaAtributos;
    private ClusterEvaluation eval;
    private Perfil perfiles;
    private String [] perfilesNuevo;
    private double [] etiquetasClusters;
    private double [] etiquetasClustersTmp;

    /**
     * Constructor de la clase ClassficateUtil, al que le tendremos que pasar una seria de propiedades para que pueda clasificar
     * @param instancia la lista de instancias
     * @param listaElementos la lista de elementos que nuestro cluster ha usado
     * @param listaAtributos la lista de atributos que nuestro cluster ha usado
     * @param eval el objeto ClusterEvaluation que ha generado nuestro clustering
     */
    public ClassificateUtil(Instances instanciaEntera,double [] etiquetasClusters,ArrayList<ArrayList<DTODataMining>> listaElementos,ArrayList<Attribute> listaAtributos,ClusterEvaluation eval, Perfil perfiles) {
        this.instanciaEntera=instanciaEntera;
        this.listaElementos=listaElementos;        
        this.listaAtributos=listaAtributos;
        this.eval=eval;
        this.etiquetasClusters=etiquetasClusters;        
        this.perfiles=perfiles;
        etiquetadoPerfil();

      

    }
    
     /**
     * Metodo que se encargará de etiquetar el perfil, para ello utilizara la distancia de manhattan que llegara
     * en el array de double llamado etiquetaClusters     
     */

    private void etiquetadoPerfil(){

        perfilesNuevo=new String[3];
        perfilesNuevo[0]=perfiles.getProfile(0).toString();
        perfilesNuevo[1]=perfiles.getProfile(1).toString();
        perfilesNuevo[2]=perfiles.getProfile(2).toString();


        if ((etiquetasClusters[0]==etiquetasClusters[1])&&(etiquetasClusters[0]==etiquetasClusters[2])){
            perfiles.setProfile(0, perfilesNuevo[0]);
            perfiles.setProfile(1, perfilesNuevo[1]);
            perfiles.setProfile(2, perfilesNuevo[2]);
        }
        else{
            if ((etiquetasClusters[0]>etiquetasClusters[1])&&(etiquetasClusters[0]>etiquetasClusters[2])){
            perfiles.setProfile(0, perfilesNuevo[2]);
            }
            else if((etiquetasClusters[0]<etiquetasClusters[1])&&(etiquetasClusters[0]<etiquetasClusters[2])){
                perfiles.setProfile(0, perfilesNuevo[0]);
            }
            else perfiles.setProfile(0, perfilesNuevo[1]);

            if ((etiquetasClusters[1]>etiquetasClusters[0])&&(etiquetasClusters[1]>etiquetasClusters[2])){
            perfiles.setProfile(1, perfilesNuevo[2]);
            }
            else if((etiquetasClusters[1]<etiquetasClusters[0])&&(etiquetasClusters[1]<etiquetasClusters[2])){
                perfiles.setProfile(1, perfilesNuevo[0]);
            }
            else perfiles.setProfile(1, perfilesNuevo[1]);

            if ((etiquetasClusters[2]>etiquetasClusters[0])&&(etiquetasClusters[2]>etiquetasClusters[1])){
            perfiles.setProfile(2, perfilesNuevo[2]);
            }
            else if((etiquetasClusters[2]<etiquetasClusters[0])&&(etiquetasClusters[2]<etiquetasClusters[1])){
                perfiles.setProfile(2, perfilesNuevo[0]);
            }
            else perfiles.setProfile(2, perfilesNuevo[1]);
        }
   }


    /**
     * Metodo que se encargará de clasificar a una lista de alumnos, añadiendo primero la información
     * de los clusteres a la clase Instances para que el algoritmo de clasificación lo tenga en cuenta,
     * IB1 en este caso
     * @param alumnos lista de alumnos a clasificar
     */


    public List<DTOPerfilUnicoAlumno> clasificate(List<DTODataMining> alumnos){
        //añadimos la clase a la que pertenece cada alumno como ultimo atributo
        //addClusterAsAttribute();
        //addClusterAsAttributeRemasterizedFiltrada();
        addClusterAsAttributeRemasterizedEntera();
        //tenemos que clasificar cada alumno
        ArrayList<DTOPerfilUnicoAlumno> listaAlumnos = new ArrayList<DTOPerfilUnicoAlumno>();
      //  IB1 ib1Class = new IB1();

        double cluster;
      //Crea e inicializa el clasificador k-nn (num. vecinos + ponderacion distancia)

        IBk ib1Class = new IBk();
        ib1Class.setKNN(1);
        ib1Class.setDistanceWeighting(new SelectedTag(IBk.WEIGHT_INVERSE, IBk.TAGS_WEIGHTING));


        try {
            if(instanciaEntera==null)
                System.out.println("la instancia es null");
            else{               
                instanciasCEntera.setClass(aCluster);
                ib1Class.buildClassifier(instanciasCEntera);
                int numInstances=instanciasCEntera.numInstances();
                for (int i=0; i<numInstances; i++) {

                    cluster = ib1Class.classifyInstance(instanciasCEntera.instance(i));
                    listaAlumnos.add(new DTOPerfilUnicoAlumno(alumnos.get(i).getNombre(),cluster));
                    System.out.println(cluster);
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(ClassificateUtil.class.getName()).log(Level.SEVERE, null, ex);
        }


        return listaAlumnos;
    }
    /**
     * Metodo para clasificar un alumno
     * @param alumno El alumno a clasificar
     * @param lista la lista de alumnos
     */
    public DTOPerfilUnicoAlumno clasificateStudent(DTODataMining alumno,List<DTODataMining> lista) {
        //añadimos la clase a la que pertenece cada alumno como ultimo atributo
//        addClusterAsAttributeRemasterizedFiltrada();
        addClusterAsAttributeRemasterizedEntera();


        int i=0;

        //el alumno a clasificar
        DTOPerfilUnicoAlumno alumnoClasificado=null;        
        IBk ib1Class = new IBk();
        ib1Class.setKNN(1);
        ib1Class.setDistanceWeighting(new SelectedTag(IBk.WEIGHT_INVERSE, IBk.TAGS_WEIGHTING));

        double cluster;
        try {
            if(instanciasCEntera==null)
                System.out.println("la instancia es null");
            else{
                instanciasCEntera.setClass(aCluster);
                ib1Class.buildClassifier(instanciasCEntera);
                while(!(lista.get(i).getNombre().equals(alumno.getNombre())))
                    i++;
                //if(lista.size()-1==i) alumnoClasificado =new DTOPerfilUnicoAlumno(alumno.getNombre(),0);
              //  else{
                    cluster = ib1Class.classifyInstance(instanciasCEntera.instance(i));
                    alumnoClasificado =new DTOPerfilUnicoAlumno(alumno.getNombre(),cluster);
              //  }
            }
        } catch (Exception ex) {
            Logger.getLogger(ClassificateUtil.class.getName()).log(Level.SEVERE, null, ex);
            //alumnoClasificado =new DTOPerfilUnicoAlumno(alumno.getNombre(),0);
            return alumnoClasificado;
        }

        return alumnoClasificado;
    }
     /**
     * Metodo que añade el cluster como instancia en nuestra serie de instancias
     */
  /* private void addClusterAsAttributeRemasterizedFiltrada() {
        //para añadir el cluster como atributo tenemos que crear una nueva serie de instancias
        //inicializamos el vector que contiene los atributos
        vectorAtributosC=new FastVector();
        FastVector vectorCluster = new FastVector(perfiles.size());
        for (int i=0;i<perfiles.size();i++)
            vectorCluster.addElement(perfiles.getProfile(i));
        aCluster=new Attribute("Clusters",vectorCluster);
        vectorAtributosC.addElement(aCluster);
        for (int i=0;i<listaAtributos.size();i++){
            vectorAtributosC.addElement(listaAtributos.get(i));
        }
        instanciasC=new Instances("rel",vectorAtributosC,10);
        for(int i=0;i<instancia.numInstances();i++){

            //añadimos todos los atributos mas el de los clusters
            Instance in=new Instance(listaElementosFiltrada.size()+1);

            for (int j=0;j<listaElementosFiltrada.size();j++){
                in.setValue(listaAtributos.get(j), Float.parseFloat(((DTODataMining)listaElementosFiltrada.get(j).get(i)).getCliks()));
            }
            try {
                in.setValue(aCluster,eval.getClusterAssignments()[i]);
                instanciasC.add(in);
            } catch (Exception ex) {
                Logger.getLogger(ClassificateUtil.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }*/

   private void addClusterAsAttributeRemasterizedEntera() {
        //para añadir el cluster como atributo tenemos que crear una nueva serie de instancias
        //inicializamos el vector que contiene los atributos
        vectorAtributosC=new FastVector();
        FastVector vectorCluster = new FastVector(perfiles.size());
        for (int i=0;i<perfiles.size();i++)
            vectorCluster.addElement(perfiles.getProfile(i));
        aCluster=new Attribute("Clusters",vectorCluster);
        vectorAtributosC.addElement(aCluster);
        for (int i=0;i<listaAtributos.size();i++){
            vectorAtributosC.addElement(listaAtributos.get(i));
        }
        instanciasCEntera=new Instances("rel",vectorAtributosC,10);
        for(int i=0;i<instanciaEntera.numInstances();i++){

            //añadimos todos los atributos mas el de los clusters
            Instance in=new Instance(listaElementos.size()+1);

            for (int j=0;j<listaElementos.size();j++){
                in.setValue(listaAtributos.get(j), Float.parseFloat(((DTODataMining)listaElementos.get(j).get(i)).getCliks()));
            }
            try {
                in.setValue(aCluster,eval.getClusterAssignments()[i]);
                instanciasCEntera.add(in);
            } catch (Exception ex) {
                Logger.getLogger(ClassificateUtil.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
